package my.edu.model.commodity.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import my.edu.common.constant.MessageConstant;
import my.edu.common.exception.CanNotFoundException;
import my.edu.common.exception.CategoryException;
import my.edu.common.exception.SaveException;
import my.edu.common.exception.UpdateException;
import my.edu.model.commodity.entity.dto.ProductCategoryDTO;
import my.edu.model.commodity.entity.vo.ProductCategoryVO;
import my.edu.model.information.entity.Supplier;
import my.edu.model.information.entity.SupplierCategory;
import org.springframework.stereotype.Service;
import my.edu.model.commodity.entity.ProductCategory;
import my.edu.model.commodity.mapper.ProductCategoryMapper;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

@Service
public class ProductCategoryServiceImpl extends ServiceImpl<ProductCategoryMapper, ProductCategory> implements IProductCategoryService{

    @Override
    public List<ProductCategoryVO> listAll(Long id) {
        List<ProductCategory> list = list();
        List<ProductCategoryVO> voList = list.stream()
                .filter(i->{
                    if (id==null)return true;
                    else if (i.getId().equals(id)) {
                        return false;
                    }else {
                        return true;
                    }
                })
                .map(i ->{
                    ProductCategoryVO vo = BeanUtil.copyProperties(i, ProductCategoryVO.class);
                    vo.setTitle(vo.getCategoryName());
                    vo.setValue(vo.getId()+"");
                    vo.setKey(vo.getId()+"");
                    return vo;
                }).toList();
        List<ProductCategoryVO> res=new ArrayList<>();
        for (ProductCategoryVO productCategoryVO : voList) {
            if (productCategoryVO.getParentId()==0){
                buildChildren(productCategoryVO,voList);
                res.add(productCategoryVO);
            }
        }

        return res;
    }

    @Override
    @Transactional
    public void saveNew(ProductCategoryDTO productCategoryDTO) {
        ProductCategory productCategory = BeanUtil.copyProperties(productCategoryDTO, ProductCategory.class);
        productCategory.setStatus(1);
        productCategory.setIsParentCategory(0);
        productCategory.setVersion(1);
        boolean updateNewParent=true;
        if (productCategory.getParentId() != 0)
            updateNewParent=checkParentAndUpdate(productCategory, true);
        if (updateNewParent)save(productCategory);
        else throw new SaveException(MessageConstant.SAVE_FAIL);

    }
    private boolean checkParentAndUpdate(ProductCategory childCategory, boolean isTurnToParent) {
        //如果检查的是修改之后的父类，则当count为0，表示此父类没有子类，所以修改子类的父类id之后，此父类的IsParentCategory值为1
        long count =0L;
        int targetValue=1;
        if (!isTurnToParent) {
            count=1L;
            targetValue=0;
        }
        boolean b =true;//代表是否检查并更新成功
        ProductCategory parentCategory;
        //检查是否从非根目录变成根目录
        if (childCategory.getParentId() == 0&&isTurnToParent){
            return true;
        }else {
            //获取所有父id是当前父id的元素
            Long parentCount = lambdaQuery()
                    .eq(ProductCategory::getParentId, childCategory.getParentId())
                    .count();
            //检查父类的子类个数，当isTurnToParent，如果parentCount为0，则新增之后要变为1
            // 否则当parentCount为1，子类修改为别的父类的时候，要将父类的IsParentCategory变为0
            if (Objects.equals(parentCount, count)) {
                //获取父id的元素
                parentCategory=lambdaQuery()
                        .eq(ProductCategory::getId, childCategory.getParentId()).one();
                if (parentCategory==null)throw new CategoryException(MessageConstant.FUCATEGORIES_NOT_FOUND);
                parentCategory.setIsParentCategory(targetValue);
                b = updateById(parentCategory);
            }
            return b;
        }

    }

    @Override
    public void updateByDTO(ProductCategoryDTO productCategoryDTO) {
        boolean updateOriginalParent=true;
        boolean updateNewParent=true;
        ProductCategory original = getById(productCategoryDTO.getId());
        //存在校验
        if (original == null) throw new CanNotFoundException(MessageConstant.CAN_NOT_FOUND);
        ProductCategory newCategory = BeanUtil.copyProperties(productCategoryDTO, ProductCategory.class);
        //将父类变成其他的，查看原先父类是否有其他子类，没有了就改isParentCategory为0
        if (!Objects.equals(newCategory.getParentId(), original.getParentId())) {
            //检查原来父类
            updateOriginalParent = checkParentAndUpdate(original, false);
            //检查修改之后的父类
            updateNewParent=checkParentAndUpdate(newCategory,true);
        }
        newCategory.setVersion(original.getVersion());
        boolean updateCategory = updateById(newCategory);
        if ( !updateOriginalParent || !updateNewParent || !updateCategory )
            throw new UpdateException(MessageConstant.UPDATE_FAIL);

    }

    @Override
    public JSONArray listAllOnly() {
        List<ProductCategory>  productCategories= list();
        JSONArray res=new JSONArray();
        for (ProductCategory supplier : productCategories) {
            JSONObject jsonObject = new JSONObject();
            jsonObject.putOnce("id",supplier.getId());
            jsonObject.putOnce("name",supplier.getCategoryName());
            res.add(jsonObject);
        }
        return res;
    }



    private void buildChildren(ProductCategoryVO parent, List<ProductCategoryVO> voList) {
        if (parent.getIsParentCategory().equals(0))return;
        List<ProductCategoryVO> children = new ArrayList<>();
        for (ProductCategoryVO vo : voList) {
            if (vo.getParentId()!=null&&vo.getParentId().equals(parent.getId())){
                buildChildren(vo,voList);
                children.add(vo);
            }
        }
        parent.setChildren(children);
    }
}
